﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Basmus.DataStructures.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Specialized;

namespace Basmus.BindingFramework
{
	public static class Extension
	{
		public static ITuple<string> ToIdentityTuple(this string identityString, string identitySeparator)
		{
			var identitySeparators = new string[1] { identitySeparator };
			var identityTuple = identityString.Split(identitySeparators, StringSplitOptions.RemoveEmptyEntries);
			if (identityTuple.Length==1)
			{
				return new Tuple<string>(identityTuple[0]);
			}
			else
			{
				return new Tuple<string>(identityTuple);
			}
			
		}
		public static ITuple<string[]> ToIdentityKeysTuple(this ITuple<string> sourceTuple, string identityKeySeparator)
		{
			var identityKeySeparators = new string[1] { identityKeySeparator };
			var identityKeysTuple = sourceTuple.Select(x => x.Split(identityKeySeparators, StringSplitOptions.RemoveEmptyEntries));
			return identityKeysTuple;
		}
		public static ITuple<string> ToIdentityTuple(this ITuple<string[]> identityKeysTuple, string identityKeySeparator)
		{
			var identityTuple = identityKeysTuple.Select(x => x.Aggregate((a, b) => a + identityKeySeparator + b));
			return identityTuple;
		}
		public static string ToIdentityString(this ITuple<string> identityTuple, string identitySeparator)
		{
			var identityString = identityTuple.IsEnumerable ? identityTuple.Elements.Aggregate((a, b) => a + identitySeparator + b) : identityTuple.Element;
			return identityString;
		}
		public static ITuple<object[]> ToIdentityObjectsTuple(this ITuple<string[]> identityKeysTuple , Type[] IdentityObjectType)
		{
			Func<string[], object[]> func = s =>
				{
					if (s.Length == IdentityObjectType.Length)
					{
						object[] identityObjects = new object[s.Length];
						for (int i = 0; i < s.Length; i++)
						{
							identityObjects[i] = Convert.ChangeType(s[i], IdentityObjectType[i]);
						}
						return identityObjects;
					}
					else
					{
						throw new Exception();
					}
				};
			return identityKeysTuple.Select(func);
		}
		public static ITuple<string[]> ToIdentityKeysTuple(this ITuple<object[]> identityObjectsTuple)
		{
			return identityObjectsTuple.Select(x => x.Select(y => y.ToString()).ToArray());
		}
		public static IEnumerable<Pair<string, string>> ToComponentSystemSheme(this NameValueCollection nameValueCollection)
		{
			foreach (var key in nameValueCollection.AllKeys)
			{
				var pair = new Pair<string, string> { First = key, Second = nameValueCollection[key] };
				yield return pair;
			}
		}
		public static NameValueCollection ToNameValueCollection(this IEnumerable<Pair<string, string>> componentSystemSheme)
		{
			var nameValueCollection = new NameValueCollection();
			foreach (var pair in componentSystemSheme)
			{
				nameValueCollection.Add(pair.First, pair.Second);
			}
			return nameValueCollection;
		}
		public static Expression PropertyConditionExpression(this Expression entity, PropertyInfo[] properties, object[] propertyValues)
		{
			var propertyConditionExpression = properties.Select((property, index) =>
				{
					var entityProperty = Expression.Property(entity, property);
					var propertyValue = Expression.Constant(propertyValues[index], property.PropertyType);
					var equalEx = Expression.Equal(entityProperty, propertyValue);
					return equalEx;
				}).Aggregate((a, b) => Expression.And(a, b));
			return propertyConditionExpression;
		}
		public static Expression PropertyConditionExpression(this Expression entity, PropertyInfo[] properties, IEnumerable<object[]> propertyValues)
		{
			var propertyConditionExpression = propertyValues
				.Select(x => entity.PropertyConditionExpression(properties, x))
				.Aggregate((a, b) => Expression.Or(a, b));
			return propertyConditionExpression;
		}
	}
}
